home *** CD-ROM | disk | FTP | other *** search
- /*
- * blob.c
- *
- * Copyright (C) 1990, 1991, Mark Podlipec, Craig E. Kolb
- * All rights reserved.
- *
- * This software may be freely copied, modified, and redistributed
- * provided that this copyright notice is preserved on all copies.
- *
- * You may not distribute this software, in whole or in part, as part of
- * any commercial product without the express consent of the authors.
- *
- * There is no warranty or other guarantee of fitness of this software
- * for any purpose. It is provided solely "as is".
- *
- * blob.c,v 4.1 1994/08/09 07:58:00 explorer Exp
- *
- * blob.c,v
- * Revision 4.1 1994/08/09 07:58:00 explorer
- * Bump version to 4.1
- *
- * Revision 1.1.1.1 1994/08/08 04:52:05 explorer
- * Initial import. This is a prerelease of 4.0.6enh3, or 4.1 possibly.
- *
- * Revision 2.1 1992/06/02 14:08:51 mcgregor
- * Installed the individual metaball surface support. A step up from the
- * individual color specification support. !NB! Attenuation adjustment may
- * look kludgy, but a clear model of how to "blend" attenuation values is
- * not available right now.
- *
- * Revision 1.1.1.1 1992/05/08 17:50:59 mcgregor
- * This baby is working!!!!! I placed the metaball_surface_contrib
- * call in BlobIntersect per Mark's suggestion. Next-- SURFACES!
- *
- * Revision 1.2 1992/05/07 20:23:45 mcgregor
- * This version works, again, at generating a multiple colored blob primitive
- * with full texturing. The bug pointed out by Mark Podlipec still exists:
- * a shadowed (or is it non-shadowed?) surface uses the ambient value from
- * the last trip through this code. It has to do with BlobNormal _NOT_
- * being called for some things. I just want to save a working edition even
- * if it is only 90% working.
- *
- * Revision 1.1 1992/04/27 20:17:23 mcgregor
- * Initial revision
- *
- * Revision 4.0 91/07/17 14:36:07 kolb
- * Initial version.
- *
- */
- #include "libcommon/common.h"
- #include "libsurf/surface.h"
- #include "geom.h"
- #include "blob.h"
-
- static Methods *iBlobMethods = NULL;
- static char blobName[] = "blob";
-
- unsigned long BlobTests, BlobHits;
- Surface init_surf; /* Preserve the surface details as found in input file */
-
- /*
- * Blob/Metaball Description
- *
- * In this implementation a Blob is made up of a threshold T, and a
- * group of 1 or more Metaballs. Each metaball 'i' is defined by
- * its position (xi,yi,zi), its radius ri, and its strength si.
- * Around each Metaball is a density function di(Ri) defined by:
- *
- * di(Ri) = c4i * Ri^4 + c2i * Ri^2 + c0i 0 <= Ri <= ri
- * di(Ri) = 0 ri < Ri
- *
- * where
- * c4i = si / (ri^4)
- * c2i = -(2 * si) / (ri^2)
- * c0i = si
- * Ri^2 is the distance from a point (x,y,z) to the center of
- * the Metaball - (xi,yi,zi).
- *
- * The density function looks sort of like a W (Float-u) with the
- * center hump crossing the d-axis at si and the two humps on the
- * side being tangent to the R-axis at -ri and +ri. Only the
- * range [0,ri] is being used.
- * I chose this function so that derivative = 0 at the points 0 and +ri.
- * This keeps the surface smooth when the densities are added. I also
- * wanted no Ri^3 and Ri terms, since the equations are easier to
- * solve without them. This led to the symmetry about the d-axis and
- * the derivative being equal to zero at -ri as well.
- *
- * The surface of the Blob is defined by:
- *
- *
- * N
- * ---
- * F(x,y,z) = \ di(Ri) = T
- * /
- * ---
- * i=0
- *
- * where
- *
- * di(Ri) is given above
- * Ri^2 = (x-xi)^2 + (y-yi)^2 + (z-zi)^2
- * N is number of Metaballs in Blob
- * T is the threshold
- * (xi,yi,zi) is the center of Metaball i
- *
- */
-
- /*****************************************************************************
- * Create & return reference to a metaball.
- * gnm 4-30-92 added reference to blob's surface
- */
- Blob *
- BlobCreate(surf, T, mlist, npoints)
- Surface *surf; /* surface reference for the blob */
- Float T; /* Treshold */
- MetaList *mlist; /* Pointer to linked list of metaballs */
- int npoints; /* Number of metaballs in blob instance */
- {
- Blob *blob;
- int i;
- MetaList *cur;
-
- /*
- * There has to be at least one metaball in the blob.
- * Note: if there's only one metaball, the blob
- * will be a sphere.
- */
- if (npoints < 1)
- {
- RLerror(RL_WARN, "blob field not correct.\n");
- return (Blob *)NULL;
- };
-
-
- blob = (Blob *)Malloc(sizeof(Blob));
-
- if((blob->surf = surf) != NULL)
- {
- /* save the original surface details ...er... oops this'll
- only save the most *recent* blob instance's surface.
- I have a plan to save each blob's (and metaballs' ??!)
- surface, but I'll implement that later.
- */
- save_orig_master_surf(surf);
- };
- blob->T = T;
- blob->list=(MetaVector *)Malloc((unsigned)(npoints*sizeof(MetaVector)));
- blob->num = npoints;
-
- /* blob will, initially be single color, not multicolored. */
- blob->MColor_Flag = FALSE;
-
- /*
- * Initialize Metaball list
- */
- for(i=0;i<npoints;i++)
- {
- cur = mlist;
- if ( ( (cur->mvec.c0 > -EPSILON) && (cur->mvec.c0 < EPSILON) )
- || (cur->mvec.rs < EPSILON) )
- {
- RLerror(RL_WARN,"Degenerate metaball in blob (sr).\n");
- return (Blob *)NULL;
- };
-
- /* store radius squared */
- blob->list[i].rs = cur->mvec.rs * cur->mvec.rs;
-
- /* Calculate and store coefficients for each metaball */
- blob->list[i].c0 = cur->mvec.c0;
- blob->list[i].c2 = -(2.0 * cur->mvec.c0) / blob->list[i].rs;
- blob->list[i].c4 = cur->mvec.c0 / (blob->list[i].rs * blob->list[i].rs);
- blob->list[i].x = cur->mvec.x;
- blob->list[i].y = cur->mvec.y;
- blob->list[i].z = cur->mvec.z;
-
- blob->list[i].surf = cur->mvec.surf;
-
- /* store metaball black body color info
- blob->list[i].mcolor.red = cur->mvec.mcolor.red;
- blob->list[i].mcolor.green = cur->mvec.mcolor.green;
- blob->list[i].mcolor.blue = cur->mvec.mcolor.blue;
- */
-
- /* If any mcolor value is != 1.0 we need to assume that
- this blob will be multi colored.
- if((blob->list[i].mcolor.red != 1.0)
- || (blob->list[i].mcolor.green != 1.0)
- || (blob->list[i].mcolor.blue != 1.0))
- */
-
- /* if the surf spec is non-NULL then we have a multisurfaced blob */
- if(blob->list[i].surf != NULL)
- blob->MColor_Flag = TRUE;
-
- mlist = mlist->next;
- free((voidstar)cur);
- };
-
- /*
- * Allocate room for Intersection Structures and
- * Allocate room for an array of pointers to point to
- * the Intersection Structures.
- */
- blob->ilist = (MetaInt *)Malloc( 2 * blob->num * sizeof(MetaInt));
- blob->iarr = (MetaInt **)Malloc( 2 * blob->num * sizeof(MetaInt *));
- return blob;
- }
-
-
-
- /* :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
- *
- * Function: save_orig_master_surf(surf)
- * Surface *surf;
- *
- * Saves the original, master surface description(if any).
- *
- * Errors:
- *
- * Notes: This needs some _SERIOUS_ reworking!
- *
- * --------------------------------------------------------------------
- * who when what
- * --------------------------------------------------------------------
- * GN McGregor
- * --------------------------------------------------------------------
- */
-
- int
- save_orig_master_surf(surf)
- Surface *surf;
- {
-
-
- init_surf.name = surf->name; /* Name */
- init_surf.amb.r = surf->amb.r; /* Ambient 'curve' */
- init_surf.amb.g = surf->amb.g; /* Ambient 'curve' */
- init_surf.amb.b = surf->amb.b; /* Ambient 'curve' */
- init_surf.diff.r = surf->diff.r; /* Diffuse reflection 'curve' */
- init_surf.diff.g = surf->diff.g; /* Diffuse reflection 'curve' */
- init_surf.diff.b = surf->diff.b; /* Diffuse reflection 'curve' */
- init_surf.spec.r = surf->spec.r; /* Specular reflection 'curve' */
- init_surf.spec.g = surf->spec.g; /* Specular reflection 'curve' */
- init_surf.spec.b = surf->spec.b; /* Specular reflection 'curve' */
- init_surf.translu.r = surf->translu.r; /* Diffuse transmission 'curve' */
- init_surf.translu.g = surf->translu.g; /* Diffuse transmission 'curve' */
- init_surf.translu.b = surf->translu.b; /* Diffuse transmission 'curve' */
- init_surf.body.r = surf->body.r; /* Specular transmission 'curve' */
- init_surf.body.g = surf->body.g; /* Specular transmission 'curve' */
- init_surf.body.b = surf->body.b; /* Specular transmission 'curve' */
- init_surf.srexp = surf->srexp; /* Specular reflection exponent */
- init_surf.stexp = surf->stexp; /* Specular transmission exponent */
- init_surf.statten = surf->statten; /* Specular transmission attenuation */
- init_surf.index = surf->index; /* Index of refraction */
- init_surf.reflect = surf->reflect; /* Specular reflectivity */
- init_surf.transp = surf->transp; /* Specular transmittance */
- init_surf.translucency = surf->translucency; /* Diffuse transmittance */
- init_surf.noshadow = surf->noshadow; /* No shadowing? */
- init_surf.next = surf->next; /* Next surface in list (if any) */
-
- return;
- }
-
-
- /* :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
- *
- * Function: Methods *BlobMethods()
- *
- *
- * Errors:
- *
- * Notes:
- *
- * --------------------------------------------------------------------
- * who when what
- * --------------------------------------------------------------------
- * GN McGregor
- * --------------------------------------------------------------------
- */
-
- Methods *
- BlobMethods()
- {
- if (iBlobMethods == (Methods *)NULL)
- {
- iBlobMethods = MethodsCreate();
- iBlobMethods->create = (GeomCreateFunc *)BlobCreate;
- iBlobMethods->methods = BlobMethods;
- iBlobMethods->name = BlobName;
- iBlobMethods->intersect = BlobIntersect;
- iBlobMethods->normal = BlobNormal;
- iBlobMethods->bounds = BlobBounds;
- iBlobMethods->stats = BlobStats;
- iBlobMethods->checkbounds = TRUE;
- iBlobMethods->closed = TRUE;
- };
- return(iBlobMethods);
- }
-
- /*****************************************************************************
- * Function used by qsort() when sorting the Ray/Blob intersection list
- */
- int
- MetaCompare(A,B)
- char *A,*B;
- {
- MetaInt **AA,**BB;
-
- AA = (MetaInt **) A;
- BB = (MetaInt **) B;
- if (AA[0]->bound == BB[0]->bound)
- return(0);
- if (AA[0]->bound < BB[0]->bound)
- return(-1);
- return(1); /* AA[0]->bound is > BB[0]->bound */
- }
-
- /*****************************************************************************
- * Ray/metaball intersection test.
- */
-
- int
- BlobIntersect(blob, ray, mindist, maxdist)
- Blob *blob;
- Ray *ray;
- Float mindist, *maxdist;
- {
- double c[5], root;
- Float dist;
- MetaInt *ilist,**iarr;
- register int i,j,inum;
- extern void qsort();
- int metaball_surface_contrib(); /* Modify surface details accord. to di(Ri) */
- BlobTests++;
-
- ilist = blob->ilist;
- iarr = blob->iarr;
-
-
- /*
- * The first step in calculating the Ray/Blob intersection is to
- * divide the Ray into intervals such that only a fixed set of
- * Metaballs contribute to the density function along that interval.
- * This is done by finding the set of intersections between the Ray
- * and each Metaball's Sphere/Region of influence, which has a
- * radius ri and is centered at (xi,yi,zi).
- * Intersection information is kept track of in the MetaInt
- * structure and consists of:
- *
- * type indicates whether this intersection is the start(R_START)
- * of a Region or the end(R_END) of one.
- * pnt the Metaball of this intersection
- * bound the distance from Ray origin to this intersection
- *
- * This list is then sorted by bound and used later to find the Ray/Blob
- * intersection.
- */
-
- inum = 0;
- for(i=0; i < blob->num; i++) /* Check all metaballs for intersection */
- {
- register Float xadj, yadj, zadj;
- register Float b, t, rs;
- register Float dmin,dmax;
-
- rs = blob->list[i].rs;
- xadj = blob->list[i].x - ray->pos.x;
- yadj = blob->list[i].y - ray->pos.y;
- zadj = blob->list[i].z - ray->pos.z;
-
- /*
- * Ray/Sphere of Influence intersection
- */
- b = xadj * ray->dir.x + yadj * ray->dir.y + zadj * ray->dir.z;
- t = b * b - xadj * xadj - yadj * yadj - zadj * zadj + rs;
-
- /*
- * Don't accept imaginary or single roots. A single root is a ray
- * tangent to the Metaball's Sphere/Region. The Metaball's
- * contribution to the overall density function at this point is
- * zero anyway.
- */
- if (t > 0.0) /* we have two roots and an intersection*/
- {
- t = sqrt(t);
- dmin = b - t;
- /*
- * only interested in stuff in front of ray origin
- */
- if (dmin < mindist + EPSILON) dmin = mindist + EPSILON;
- dmax = b + t;
- if (dmax > dmin) /* we have a valid Region */
- {
- /*
- * Initialize min/start and max/end Intersections Structures
- * for this Metaball
- */
- ilist[inum].type = R_START;
- ilist[inum].pnt = i;
- ilist[inum].bound = dmin;
- for(j=0;j<5;j++) ilist[inum].c[j] = 0.0;
- iarr[inum] = &(ilist[inum]);
- inum++;
-
- ilist[inum].type = R_END;
- ilist[inum].pnt = i;
- ilist[inum].bound = dmax;
- for(j=0;j<5;j++) ilist[inum].c[j] = 0.0;
- iarr[inum] = &(ilist[inum]);
- inum++;
- }; /* End of valid Region */
- }; /* End of two roots */
- }; /* End of loop through metaballs */
-
- /*
- * If there are no Ray/Metaball intersections there will
- * not be a Ray/Blob intersection. Exit now.
- */
- if (inum == 0)
- {
- return FALSE;
- }
-
- /*
- * Sort Intersection list. No sense using qsort if there's only
- * two intersections.
- *
- * Note: we actually aren't sorting the Intersection structures, but
- * an array of pointers to the Intersection structures.
- * This is faster than sorting the Intersection structures themselves.
- */
- if (inum==2)
- {
- MetaInt *t;
- if (ilist[0].bound > ilist[1].bound)
- {
- t = iarr[0];
- iarr[0] = iarr[1];
- iarr[1] = t;
- };
- }
- else
- qsort((voidstar)(iarr), (unsigned)inum, sizeof(MetaInt *), MetaCompare);
-
- /*
- * Finding the Ray/Blob Intersection
- *
- * The non-zero part of the density function for each Metaball is
- *
- * di(Ri) = c4i * Ri^4 + c2i * Ri^2 + c0i
- *
- * To find find the Ray/Blob intersection for one metaball
- * substitute for distance
- *
- * Ri^2 = (x-xi)^2 + (y-yi)^2 + (z-zi)^2
- *
- * and then substitute the Ray equations:
- *
- * x = x0 + x1 * t
- * y = y0 + y1 * t
- * z = z0 + z1 * t
- *
- * to get a big mess :^). Actually, it's a Quartic in t and it's fully
- * listed farther down. Here's a short version:
- *
- * c[4] * t^4 + c[3] * t^3 + c[2] * t^2 + c[1] * t + c[0] = T
- *
- * Don't forget that the Blob is defined by the density being equal to
- * the threshold T.
- * To calculate the intersection of a Ray and two or more Metaballs,
- * the coefficients are calculated for each Metaball and then added
- * together. We can do this since we're working with polynomials.
- * The points of intersection are the roots of the resultant equation.
- *
- * The algorithm loops through the intersection list, calculating
- * the coefficients if an intersection is the start of a Region and
- * adding them to all intersections in that region.
- * When it detects a valid interval, it calculates the
- * roots from the starting intersection's coefficients and if any of
- * the roots are in the interval, the smallest one is returned.
- *
- */
-
- { /* This curly brace is for variable scoping control. */
- register Float *tmpc;
- MetaInt *strt,*tmp;
- register int istrt,itmp;
- register int num,exitflag,inside;
- int clear;
-
- /*
- * Start the algorithm outside the first interval
- */
- inside = 0;
- istrt = 0;
- strt = iarr[istrt];
- if (strt->type != R_START)
- RLerror(RL_WARN,"MetaInt sanity check FAILED!\n");
-
- /*
- * Loop through intersection. If a root is found the code
- * will return at that point.
- */
- while( istrt < inum ) /* inum ==> number of intersections aka iarr entries */
- {
- /*
- * Check for multiple intersections at the same point.
- * This is also where the coefficients are calculated
- * and spread throughout that Metaball's sphere of
- * influence.
- */
- do /* BEGIN: search for valid interval(s) */
- {
- /* find out which metaball */
- i = strt->pnt;
- /* only at starting boundaries do this */
- if (strt->type == R_START)
- {
- register MetaVector *ml;
- register Float a1,a0;
- register Float xd,yd,zd;
- register Float c4,c2,c0;
-
- /* multi colored blob variables */
- register Float Ri2; /* Ri^2 */
- register Float Ri4; /* Ri^4 */
- register Float DF; /* di(Ri) / T */
-
- /* we're inside */
- inside++;
-
- /* As promised, the full equations
- *
- * c[4] = c4*a2*a2;
- * c[3] = 4.0*c4*a1*a2;
- * c[2] = 4.0*c4*a1*a1 + 2.0*c4*a2*a0 + c2*a2;
- * c[1] = 4.0*c4*a1*a0 + 2.0*c2*a1;
- * c[0] = c4*a0*a0 + c2*a0 + c0;
- *
- * where
- * a2 = (x1*x1 + y1*y1 + z1*z1) = 1.0 because the ray
- * is normalized
- * a1 = (xd*x1 + yd*y1 + zd*z1)
- * a0 = (xd*xd + yd*yd + zd*zd)
- * xd = (x0 - xi)
- * yd = (y0 - yi)
- * zd = (z0 - zi)
- * (xi,yi,zi) is center of Metaball
- * (x0,y0,z0) is Ray origin
- * (x1,y1,z1) is normalized Ray direction
- * c4,c2,c0 are the coefficients for the
- * Metaball's density function
- *
- */
- /*
- * Some compilers would recalculate
- * this each time its used.
- */
- ml = &(blob->list[i]);
-
- xd = ray->pos.x - ml->x;
- yd = ray->pos.y - ml->y;
- zd = ray->pos.z - ml->z;
- a1 = (xd * ray->dir.x + yd * ray->dir.y + zd * ray->dir.z);
- a0 = (xd * xd + yd * yd + zd * zd);
- c0 = ml->c0;
- c2 = ml->c2;
- c4 = ml->c4;
- c[4] = c4;
- c[3] = 4.0*c4*a1;
- c[2] = 2.0*c4*(2.0*a1*a1 + a0) + c2;
- c[1] = 2.0*a1*(2.0*c4*a0 + c2);
- c[0] = c4*a0*a0 + c2*a0 + c0;
-
- /*
- * Since we've gone through the trouble of calculating the
- * coefficients, put them where they'll be used.
- * Starting at the current intersection(It's also the start of
- * a region), add the coefficients to each intersection until
- * we reach the end of this region.
- */
- itmp = istrt;
- tmp = strt;
- while( (tmp->pnt != i) || (tmp->type != R_END) )
- {
- tmpc = tmp->c;
- for(j=0;j<5;j++)
- *tmpc++ += c[j];
- itmp++;
- tmp = iarr[itmp];
- }
-
- } /* End of start of a Region */
- /*
- * Since the intersection wasn't the start
- * of a region, it must the end of one.
- */
- else
- inside--;
-
- /*
- * If we are inside a region(or regions) and the next
- * intersection is not at the same place, then we have
- * the start of an interval. Set the exitflag.
- */
- if ((inside > 0)
- && (strt->bound != iarr[istrt+1]->bound) )
- exitflag = 1;
- else
- /* move to next intersection */
- {
- istrt++;
- strt = iarr[istrt];
- exitflag = 0;
- }
- /*
- * Check to see if we're at the end. If so then exit with
- * no intersection found.
- */
- if (istrt >= inum)
- {
- return FALSE;
- }
- }
- while(!exitflag); /* END: of Search for valid interval (do-while) */
-
- /*
- * Find Roots along this interval
- */
-
- /* get coefficients from Intersection structure */
- tmpc = strt->c;
- for(j=0;j<5;j++)
- c[j] = *tmpc++;
-
- /* Don't forget to put in threshold */
- c[0] -= blob->T;
-
- /* Use Graphic Gem's Quartic Root Finder */
- num = FindRoot(c,4,strt->bound,iarr[istrt+1]->bound,&root,-1);
-
-
- if ( num && (root > mindist) && (root < *maxdist) )
- {
- *maxdist = root;
- BlobHits++;
- if(blob->MColor_Flag)
- metaball_surface_contrib(blob,ray,root);
- return TRUE;
- }
-
- /*
- * Move to next intersection
- */
- istrt++;
- strt = iarr[istrt];
-
- }; /* End of loop through Intersection List */
- }; /* End of Solving for Ray/Blob Intersection */
- /*
- * return negative
- */
- return FALSE;
- }
-
-
- /***********************************************
- * Find the Normal of a Blob at a given point
- *
- * The normal of a surface at a point (x0,y0,z0) is the gradient of that
- * surface at that point. The gradient is the vector
- *
- * Fx(x0,y0,z0) , Fy(x0,y0,z0) , Fz(x0,y0,z0)
- *
- * where Fx(),Fy(),Fz() are the partial dervitives of F() with respect
- * to x,y and z respectively. Since the surface of a Blob is made up
- * of the sum of one or more polynomials, the normal of a Blob at a point
- * is the sum of the gradients of the individual polynomials at that point.
- * The individual polynomials in this case are di(Ri) i = 0,...,num .
- *
- * To find the gradient of the contributing polynomials
- * take di(Ri) and substitute U = Ri^2;
- *
- * di(U) = c4i * U^2 + c2i * U + c0i
- *
- * dix(U) = 2 * c4i * Ux * U + c2i * Ux
- *
- * U = (x-xi)^2 + (y-yi)^2 + (z-zi)^2
- *
- * Ux = 2 * (x-xi)
- *
- * Rearranging we get
- *
- * dix(x0,y0,z0) = 4 * c4i * xdi * disti + 2 * c2i * xdi
- * diy(x0,y0,z0) = 4 * c4i * ydi * disti + 2 * c2i * ydi
- * diz(x0,y0,z0) = 4 * c4i * zdi * disti + 2 * c2i * zdi
- *
- * where
- * xdi = x0-xi
- * ydi = y0-yi
- * zdi = y0-yi
- * disti = xdi*xdi + ydi*ydi + zdi*zdi
- * (xi,yi,zi) is the center of Metaball i
- * c4i,c2i,c0i are the coefficients of Metaball i's density function
- */
-
- int
- BlobNormal(blob, pos, nrm, gnrm)
- Blob *blob;
- Vector *pos, *nrm, *gnrm;
- {
- register int i;
- int clear;
-
- /*
- * Initialize normals to zero
- */
- nrm->x = nrm->y = nrm->z = 0.0;
-
- /*
- * Loop through Metaballs. If the point is within a Metaball's
- * Sphere of influence, calculate the gradient and add it to the
- * normals
- */
- for(i=0;i < blob->num; i++)
- {
- register MetaVector *sl;
- register Float dist,xd,yd,zd;
-
- sl = &(blob->list[i]);
- xd = pos->x - sl->x;
- yd = pos->y - sl->y;
- zd = pos->z - sl->z;
-
- dist = xd*xd + yd*yd + zd*zd;
- if (dist <= sl->rs )
- {
- register Float temp;
- register Float Ri4, Ri2, DF;
-
- /* temp is negative so normal points out of blob */
- temp = -2.0 * (2.0 * sl->c4 * dist + sl->c2);
- nrm->x += xd * temp;
- nrm->y += yd * temp;
- nrm->z += zd * temp;
-
- };
- };
- (void)VecNormalize(nrm);
- *gnrm = *nrm;
- return FALSE;
- }
-
-
- /*****************************************************************************
- * Calculate the extent of the Blob
- */
- void
- BlobBounds(blob, bounds)
- Blob *blob;
- Float bounds[2][3];
- {
- Float r;
- Float minx,miny,minz,maxx,maxy,maxz;
- int i;
-
- /*
- * Loop through Metaballs to find the minimun and maximum in each
- * direction.
- */
- for( i=0; i< blob->num; i++)
- {
- register Float d;
-
- r = sqrt(blob->list[i].rs);
- if (i==0)
- {
- minx = blob->list[i].x - r;
- miny = blob->list[i].y - r;
- minz = blob->list[i].z - r;
- maxx = blob->list[i].x + r;
- maxy = blob->list[i].y + r;
- maxz = blob->list[i].z + r;
- }
- else
- {
- d = blob->list[i].x - r;
- if (d<minx) minx = d;
- d = blob->list[i].y - r;
- if (d<miny) miny = d;
- d = blob->list[i].z - r;
- if (d<minz) minz = d;
- d = blob->list[i].x + r;
- if (d>maxx) maxx = d;
- d = blob->list[i].y + r;
- if (d>maxy) maxy = d;
- d = blob->list[i].z + r;
- if (d>maxz) maxz = d;
- };
- };
- bounds[LOW][X] = minx;
- bounds[HIGH][X] = maxx;
- bounds[LOW][Y] = miny;
- bounds[HIGH][Y] = maxy;
- bounds[LOW][Z] = minz;
- bounds[HIGH][Z] = maxz;
- return;
- }
-
- char *
- BlobName()
- {
- return blobName;
- }
-
- void
- BlobStats(tests, hits)
- unsigned long *tests, *hits;
- {
- *tests = BlobTests;
- *hits = BlobHits;
- return;
- }
-
- void
- BlobMethodRegister(meth)
- UserMethodType meth;
- {
- if (iBlobMethods)
- iBlobMethods->user = meth;
- return;
- }
-
-
-
-
- /* :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
- *
- * Function: restore_orig_surf_descrip(blob)
- * restores the original surface details as they were passed
- * into Rayshade for the blob instance.
- * Errors: None at this time.
- *
- * Notes: This _SHOULD_ bullet proof the code, but where?????
- *
- * --------------------------------------------------------------------
- * who when what
- * --------------------------------------------------------------------
- * GN McGregor 6-May-92 development revisions
- * --------------------------------------------------------------------
- */
-
- int
- restore_orig_surf_descrip(blob)
- Blob *blob;
- {
- Surface *surf;
- /* As the routine name suggests we are restoring the original surface
- description as it was handed in to the program for the blob. While
- this may be a bit of overkill, it does make this part of the code a
- bit more bullet proof.
- */
-
- if((surf = blob->surf))
- {
- surf->name = init_surf.name; /* Name */
- surf->amb.r = init_surf.amb.r; /* Ambient 'curve' */
- surf->amb.g = init_surf.amb.g; /* Ambient 'curve' */
- surf->amb.b = init_surf.amb.b; /* Ambient 'curve' */
- surf->diff.r = init_surf.diff.r; /* Diffuse reflection 'curve' */
- surf->diff.g = init_surf.diff.g; /* Diffuse reflection 'curve' */
- surf->diff.b = init_surf.diff.b; /* Diffuse reflection 'curve' */
- surf->spec.r = init_surf.spec.r; /* Specular reflection 'curve' */
- surf->spec.g = init_surf.spec.g; /* Specular reflection 'curve' */
- surf->spec.b = init_surf.spec.b; /* Specular reflection 'curve' */
- surf->translu.r = init_surf.translu.r; /* Diffuse transmission 'curve' */
- surf->translu.g = init_surf.translu.g; /* Diffuse transmission 'curve' */
- surf->translu.b = init_surf.translu.b; /* Diffuse transmission 'curve' */
- surf->body.r = init_surf.body.r; /* Specular transmission 'curve' */
- surf->body.g = init_surf.body.g; /* Specular transmission 'curve' */
- surf->body.b = init_surf.body.b; /* Specular transmission 'curve' */
- surf->srexp = init_surf.srexp; /* Specular reflection exponent */
- surf->stexp = init_surf.stexp; /* Specular transmission exponent */
- surf->statten = init_surf.statten; /* Specular transmission attenuation */
- surf->index = init_surf.index; /* Index of refraction */
- surf->reflect = init_surf.reflect; /* Specular reflectivity */
- surf->transp = init_surf.transp; /* Specular transmittance */
- surf->translucency = init_surf.translucency; /* Diffuse transmittance */
- surf->noshadow = init_surf.noshadow; /* No shadowing? */
- surf->next = init_surf.next; /* Next surface in list (if any) */
-
- };
- return(GOOD);
- }
-
-
- /* :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
- *
- * Function: metaball_surface_contrib(blob, ray, dist)
- *
- *
- * Errors:
- *
- * Notes:
- *
- * --------------------------------------------------------------------
- * who when what
- * --------------------------------------------------------------------
- * GN McGregor
- * --------------------------------------------------------------------
- */
- int
- metaball_surface_contrib(blob, ray, dist)
- Blob *blob;
- Ray *ray;
- Float dist;
- {
- Vector intersect_pos;
- int i;
-
- /* We have the distance from the ray's origin to the point of intersection.
- We have to find the x, y, z values for the point equal to dist
- along the ray.The intersection x, y, z values can be drived by
- extending the unit vector like so...
- */
-
- VecAddScaled(ray->pos, dist, ray->dir, &intersect_pos);
-
- /* Prepare to modify the surface */
- tweak_blob_surf(1, blob->surf, 1.0, &(blob->list[0]));
-
- for(i=0;i < blob->num; i++) /* Scan metaballs for surface contributions */
- {
- register MetaVector *sl;
- register Float range,xd,yd,zd;
- register Float Ri2; /* R(i)^2 in Mark's Equation up above. */
-
- sl = &(blob->list[i]);
- xd = intersect_pos.x - sl->x;
- yd = intersect_pos.y - sl->y;
- zd = intersect_pos.z - sl->z;
-
- Ri2 = xd*xd + yd*yd + zd*zd;
- if (Ri2 <= sl->rs )
- {
- register Float DF;
-
- DF = (((sl->c4*Ri2) + sl->c2)*Ri2 + sl->c0) / blob->T;
- /*DF = ((sl->c4*Ri4) + (sl->c2*Ri2) + sl->c0) / blob->T;*/
- tweak_blob_surf(0, blob->surf, DF, sl->surf);
- }; /* END metaball density calc. */
- };
-
- return(GOOD);
- }
-
-
-
- /* :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
- *
- * Function: tweak_blob_surf(clear, surf, df, mcolor)
- *
- * This routine will fiddle with those components of the surface that
- * have RGB values as part of their specs. The more sophisticated
- * concept and operation would involve allowing each metaball to possess
- * its own surface. After this exercise that possibility may prove easier
- * and more useful.
- *
- *
- * Errors:
- *
- * Notes:
- *
- * --------------------------------------------------------------------
- * who when what
- * --------------------------------------------------------------------
- * GN McGregor 6-May-92 development revisions
- * --------------------------------------------------------------------
- */
-
- int
- tweak_blob_surf(clear, surf, df, msurf)
- int clear; /* flag-signal to init surface spec prior to tweaking */
- Surface *surf; /* pointer to surface spec. */
- Float df; /* density fraction-> contribution weight of metaball */
- Surface *msurf; /* metaball's surface spec. */
- {
-
- if(surf)
- {
- if(clear) /* We want to prepare the surface for its dynamic update. */
- {
- surf->amb.r = 0.0;
- surf->amb.g = 0.0;
- surf->amb.b = 0.0;
-
- surf->diff.r = 0.0;
- surf->diff.g = 0.0;
- surf->diff.b = 0.0;
-
- surf->spec.r = 0.0;
- surf->spec.g = 0.0;
- surf->spec.b = 0.0;
-
- surf->translu.r = 0.0;
- surf->translu.g = 0.0;
- surf->translu.b = 0.0;
-
- surf->body.r = 0.0;
- surf->body.g = 0.0;
- surf->body.b = 0.0;
-
- surf->srexp = 0.0;
- surf->stexp = 0.0;
- surf->statten = 0.0;
- surf->index = 0.0;
- surf->reflect = 0.0;
- surf->transp = 0.0;
- surf->translucency = 0.0;
- }
- else /* We are updating the surface components. */
- {
- /* The new surface component color is the weighted sum of
- each of the contributing metaballs colors. The weighting
- factor is fractiobnal contribution of the metaball to the
- blob's density function. ( i.e. d(i) / T ).
- */
- /* Trying out: use surface specs as a scale value. */
-
- surf->amb.r += (msurf->amb.r * df) * init_surf.amb.r;
- surf->amb.g += (msurf->amb.g * df) * init_surf.amb.g;
- surf->amb.b += (msurf->amb.b * df) * init_surf.amb.b;
-
- surf->diff.r += (msurf->diff.r * df) * init_surf.diff.r;
- surf->diff.g += (msurf->diff.g * df) * init_surf.diff.g;
- surf->diff.b += (msurf->diff.b * df) * init_surf.diff.b;
-
- surf->spec.r += (msurf->spec.r * df) * init_surf.spec.r;
- surf->spec.g += (msurf->spec.g * df) * init_surf.spec.g;
- surf->spec.b += (msurf->spec.b * df) * init_surf.spec.b;
-
- surf->translu.r += (msurf->translu.r * df) * init_surf.translu.r;
- surf->translu.g += (msurf->translu.g * df) * init_surf.translu.g;
- surf->translu.b += (msurf->translu.b * df) * init_surf.translu.b;
-
- surf->body.r += (msurf->body.r * df) * init_surf.body.r;
- surf->body.g += (msurf->body.g * df) * init_surf.body.g;
- surf->body.b += (msurf->body.b * df) * init_surf.body.b;
-
- /* Model physical behavior as sum of weighted contributions from
- metaballs.
- */
- surf->srexp += (msurf->srexp * df);/* + init_surf.srexp;*/
- surf->stexp += (msurf->stexp * df);/* + init_surf.stexp;*/
-
- /* Attenuation _is_ a problem... Let's try a method where
- the attenuation is equal to the maximum value we see.
- */
- if(msurf->statten > init_surf.statten)
- surf->statten = (msurf->statten > surf->statten) ? msurf->statten : surf->statten;
- else
- surf->statten = (init_surf.statten > surf->statten) ? init_surf.statten : surf->statten;
-
- surf->index += (msurf->index * df);/* * init_surf.index;*/
- surf->reflect += (msurf->reflect * df);/* * init_surf.reflect;*/
- surf->transp += (msurf->transp * df);/* * init_surf.transp;*/
- surf->translucency += (msurf->translucency * df);/* * init_surf.translucency;*/
- };
- };
- return(GOOD);
- }
-